package org.goldenmock.web.matchers;

import org.goldenmock.web.server.EasyHttpRequest;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.ByteArrayInputStream;

/**
 * TODO: should do something with those namespaces.
 *
 * @author Robin Wagenaar
 * @author Pascal Snippen
 * @author Arjen van Staalduinen
 */
public class ContentXPathMatcher extends EasyRequestMatcher {
    private String expectedValue;
    private XPathExpression expression;

    public ContentXPathMatcher(String expression, String expectedValue) {
        this.expectedValue = expectedValue;

        try {
            this.expression = XPathFactory.newInstance().newXPath().compile(expression);
        } catch (XPathExpressionException e) {
            throw new MatchingException(e);
        }
    }

    @Override
    public boolean matchesEasyRequest(EasyHttpRequest httpRequest) {
        String content = httpRequest.getContentAsString();
        if (content == null || content.isEmpty()) {
            return false;
        }

        try {
            DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
            domFactory.setNamespaceAware(false);
            Document doc = domFactory.newDocumentBuilder().parse(new ByteArrayInputStream(content.getBytes("UTF-8")));
            String result = (String) expression.evaluate(doc, XPathConstants.STRING);
            return expectedValue.trim().equals(result);
        } catch (SAXException e) {
            // If multiple expectations are set, and one of 'm uses this xpath-matcher, all incoming requests will
            // be validated by this matcher. And yiiihaaa, the content of the incoming httpRequest may or may not be XML.
            // Maybe think of a way to make this matcher check if the incoming requestbody is valid sampleXml before trying
            // to parse and match it.
            // PS: which may be expensive in terms of performance.
            return false;
        } catch (Exception e) {
            throw new MatchingException(e); //e may be any of these: ParserConfigurationException, IOException, XPathExpressionException
        }
    }
}
